#include "stdafx.h"
#include "OISEnv.h"
#include "../Behaviors/KeyboardInputSensor.h"
#include "../Behaviors/MouseInputSensor.h"
#include "../Behaviors/Enviroment.h"
#include "Enviroment.h"

#include <OgreRoot.h>
#include <OgreFrameListener.h>

#include "OgreSceneNodeMovingEffector.h"
#include "../Behaviors/FPController.h"



IMPLEMENT_Singleton(VWD::OISEnv)

OIS::InputManager *pInputManager = 0;
bool isOISEnabled = false;

using namespace Ogre;
using namespace Behavior;

class UIInputListener:
	public OIS::MouseListener,
	public OIS::KeyListener
{
public:
	virtual bool mouseMoved( const OIS::MouseEvent &arg ) override
	{		
		return false;
	}
	virtual bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )override
	{
		 return false;
	}
	virtual bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) override
	{
		return false;
	}
	virtual bool keyPressed( const OIS::KeyEvent &arg ) override
	{
		return false;
	}
	virtual bool keyReleased( const OIS::KeyEvent &arg ) override
	{
		return false;
	}
};

class StateChecker:
	public Ogre::FrameListener,
	public Behavior::KeyboardInputSensor,
	public Behavior::MouseInputSensor
{
private:
	OIS::Mouse *pMouse;
	OIS::Keyboard *pKeyboard;	
	UIInputListener oisListener;
	VWD::OgreSceneNodeMovingEffector *pEffector;
	Behavior::FPController *pFPC;	
public:	

	StateChecker()
	{
		OIS::ParamList pl;

		std::ostringstream windowHndStr;

		size_t windowHnd = 0;
		
		VWD::Enviroment::RenderWindow->getCustomAttribute("WINDOW", &windowHnd);
		windowHndStr << windowHnd;

		pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
#ifdef _WIN32
		pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND")));
		pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
#endif
		pInputManager = OIS::InputManager::createInputSystem(pl);			

		pMouse = pInputManager->numMice()>0?
			static_cast<OIS::Mouse*>(pInputManager->createInputObject(OIS::OISMouse,true)):0;


		pKeyboard = pInputManager->numKeyboards()>0?
			static_cast<OIS::Keyboard*>(pInputManager->createInputObject(OIS::OISKeyboard,true)):0;

		ResetMouseTrapArea();
				
		pMouse->setEventCallback(&oisListener);
		pKeyboard->setEventCallback(&oisListener);

		pEffector=new VWD::OgreSceneNodeMovingEffector(VWD::Enviroment::Camera->getParentSceneNode());
		pFPC = new Behavior::FPController();
		pFPC->SetTarget(pEffector);		
	}

	~StateChecker()
	{	
		pFPC->SetTarget(0);
		delete pFPC;
		delete pEffector;

		pKeyboard->setEventCallback(0);
		pMouse->setEventCallback(0);

		OIS::InputManager::destroyInputSystem(pInputManager);
	}

	void ResetMouseTrapArea()
	{
		if(pMouse==0)return;

		pMouse->getMouseState().width = VWD::Enviroment::RenderWindow->getWidth();
		pMouse->getMouseState().height = VWD::Enviroment::RenderWindow->getHeight();
	}

	virtual bool frameStarted(const Ogre::FrameEvent& evt) 
	{
		if(isOISEnabled)
		{
		if(pMouse!=0)
			pMouse->capture();

		if(pKeyboard!=0)
			pKeyboard->capture();

		pFPC->Update(evt.timeSinceLastFrame);		
		}				

		return true; 
	}

	virtual bool IsKeyDown(KeyboardEnums::KeyCode key) const override
	{
		return pKeyboard!=0? pKeyboard->isKeyDown((OIS::KeyCode)key):false;
	}

	virtual bool IsModifierDown(KeyboardEnums::Modifier modifier) const override
	{
		return pKeyboard!=0? pKeyboard->isModifierDown((OIS::Keyboard::Modifier)modifier):false;
	}

	virtual int GetAbsoluteX() const override 
	{
		return pMouse!=0? pMouse->getMouseState().X.abs:0;
	}

	virtual int GetRelativeX() const override 
	{
		return pMouse!=0? pMouse->getMouseState().X.rel:0;
	}

	virtual int GetAbsoluteY() const override 
	{
		return pMouse!=0? pMouse->getMouseState().Y.abs:0;
	}

	virtual int GetRelativeY() const override 
	{
		return pMouse!=0? pMouse->getMouseState().Y.rel:0;
	}

	virtual int GetAbsoluteZ() const override 
	{
		return pMouse!=0? pMouse->getMouseState().Z.abs:0;
	}

	virtual int GetRelativeZ() const override 
	{
		return pMouse!=0? pMouse->getMouseState().Z.rel:0;
	}

	virtual bool IsButtonDown(MouseEnums::MouseButton id) const override 
	{
		return pMouse!=0? pMouse->getMouseState().buttonDown((OIS::MouseButtonID)id):false;
	}

} *pStateChecker;

VWD::OISEnv::OISEnv(void)
{
}

VWD::OISEnv::~OISEnv(void)
{
}

void VWD::OISEnv::Init()
{
	pStateChecker = new StateChecker();
	Behavior::Enviroment::pKeyboardInputSensor = pStateChecker;
	Behavior::Enviroment::pMouseInputSensor = pStateChecker;
	Ogre::Root::getSingletonPtr()->addFrameListener(pStateChecker);
}

void VWD::OISEnv::Shutdown()
{
	Ogre::Root::getSingletonPtr()->removeFrameListener(pStateChecker);
	Behavior::Enviroment::pKeyboardInputSensor = 0;
	Behavior::Enviroment::pMouseInputSensor = 0;
	delete pStateChecker;
}

bool VWD::OISEnv::IsEnabled() const
{
	return isOISEnabled;
}

void VWD::OISEnv::SetEnabled( bool val )
{
	isOISEnabled = val;
}